﻿using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Objects.SqlClient;
using System.Data.SqlClient;
using System.Linq;

namespace Ndex.Core.Data
{
    public class BaseRepository : DbContext, IDisposable
    {
        #region Constructors
        public BaseRepository() : base("DefaultConnection") { }

        public BaseRepository(string connection) : base(connection) { }
        #endregion

        #region Public Methods

        public T Get<T>(long Id) where T : Entity
        {
            return Set<T>().FirstOrDefault(i => i.Id == Id);
        }

        public bool Exist<T>(long Id) where T : Entity
        {
            return Set<T>().Any(i => i.Id == Id);
        }

        public IQueryable<T> Get<T>() where T : BaseEntity
        {
            return Set<T>().AsQueryable();
        }

        public long GetMaxID<T>(long subSystemId = 0) where T : Entity
        {
            if (subSystemId == 0)
                return Get<T>().Max(i => i.Id);

            var prefix = GetPrefixForSubSystem(subSystemId);
            var query = Get<T>();
            if (prefix != string.Empty)
                query = query.Where(x => SqlFunctions.StringConvert((double)x.Id).Trim().StartsWith(prefix));

            var max = query.Max(x => x.Id);
            if (max == 0)
                max = long.Parse(prefix);

            return max;
        }

        public void InsertOrUpdate<T>(T entity, long userId = 0) where T : Entity
        {
            if (entity.Id == 0)
                Create(entity, userId);
            else
                Update(entity, userId);
        }

        public void Delete<T>(T entity) where T : BaseEntity
        {
            Entry<T>(entity).State = System.Data.EntityState.Deleted;
        }

        public void Create<T>(T entity, long userId = 0) where T : BaseEntity
        {
            if (entity is ITracking)
            {
                var data = entity as ITracking;
                data.CreatedDate = DateTime.Now;
                data.CreatedBy_Id = userId;
            }
            Set<T>().Add(entity);
        }

        public void Update<T>(T entity, long userId = 0) where T : BaseEntity
        {
            if (entity is ITracking)
            {
                var data = entity as ITracking;
                data.ModifiedDate = DateTime.Now;
                data.ModifiedBy_Id = userId;
            }
        }

        public string GetPrefixForSubSystem(long subSystemId)
        {
            var prefix = string.Empty;

            try
            {
                if (subSystemId != default(long))
                {
                    var para = new SqlParameter("@piSubsystemID", subSystemId);
                    prefix = Database.SqlQuery<string>("SELECT dbo.usf_GetPrefixSubSystem(@piSubsystemID)", para).FirstOrDefault();
                }
            }
            catch
            { }

            return prefix;
        }

        public void ExecuteStoredProcedure(string name, Dictionary<string, object> paramaters)
        {
            var dbcommand = CreateCommand(name, paramaters);
            dbcommand.ExecuteNonQuery();
            Database.Connection.Close();
        }

        public DbCommand CreateCommand(string name, Dictionary<string, object> paramaters)
        {
            Database.Connection.Open();
            var dbcommand = Database.Connection.CreateCommand();
            dbcommand.CommandType = System.Data.CommandType.StoredProcedure;
            dbcommand.CommandText = name;

            foreach (var item in paramaters)
            {
                var parameter = dbcommand.CreateParameter();
                parameter.ParameterName = item.Key;
                parameter.Value = item.Value;
                dbcommand.Parameters.Add(parameter);
            }
            dbcommand.CommandTimeout = 240; // 4 seconds
            return dbcommand;
        }

        #endregion

        void IDisposable.Dispose()
        {
            base.Dispose();
        }
    }
}
